package controllers;

import java.util.*;

import java.util.HashMap;

import models.Choice;
import models.CommunityList;
import models.Exercise;
import models.Question;
import models.RecommendTutorial;
import models.RegisteredUser;
import models.Score;
import models.Topic;
import models.Tutorial;
import models.membersInCommList;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import play.data.validation.Required;

import models.*;
import play.cache.Cache;
import play.data.validation.Email;
import play.data.validation.Equals;
import play.data.validation.Required;
import play.db.jpa.GenericModel.JPAQuery;
import play.db.jpa.Model;

import play.libs.Mail;
import play.mvc.Controller;

public class Exercises extends Controller {
	/***
	 * this method render page enterName where the exercise is created so it
	 * renders to it the specific tutorial for the exercise that will be created
	 * 
	 * @author hadeer
	 * @param tid
	 */
	public static void enterName(long tid) {
		if (session.get("RegisteredUserId") != null) {
			Tutorial tutorial = Tutorial.findById(tid);
			render(tutorial);
		} else {
			renderText("please log in to create an exercise");
		}
	}

	/***
	 * this method takes the exercise name and the tutorial id to create an
	 * exercise and renders the exercise id to the page add question to add
	 * questions to this exercise
	 * 
	 * @author dana - setting the isRandom variable
	 * @author hadeer
	 * @param entername
	 * @param exercisename
	 * @param type
	 */
	public static void createExercise(
			long entername,
			@Required(message = "Please Enter the exercise name") String exercisename,
			String type) {
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			enterName(entername);
		} else {
			if (session.get("RegisteredUserId") != null) {
				long UserId = Long.parseLong(session.get("RegisteredUserId"));

				models.RegisteredUser tempregistereduser = models.RegisteredUser
						.findById(UserId);
				models.Exercise exercise = new models.Exercise(UserId,
						entername, exercisename).save();

				boolean lessoptions = false;

				if (type.equals("random")) {
					exercise.setRandom(true);
					exercise.save();

				}
				tempregistereduser.addPoints();
				addQuestion(exercise.id);
			} else {
				renderText("please log in first to be able to create an exercise");
			}
		}

	}

	/***
	 * this method renders the page add question which renders the list of
	 * questions created to this exercise till now
	 * 
	 * @author hadeer
	 * @param exerciseid
	 * @param lessoptions
	 */
	public static void addQuestion(long exerciseid) {
		models.Exercise exercise = models.Exercise.findById(exerciseid);
		List<Question> theQuestions = exercise.getQuestions();

		render(theQuestions, exercise);
	}

	/***
	 * this method checks whether the choice(String) entered is not null
	 * 
	 * @author hadeer
	 * @param choice
	 * @return
	 */
	public static boolean checkChoiceNull(String choice) {
		if (choice.equals("")) {
			return false;
		} else {
			return true;
		}

	}

	/***
	 * this method takes the input of the question from the user and creates new
	 * question with new choices not less than two and renders again the add
	 * question page if the user had pressed the add question button to add
	 * another question ,but if pressed the end button the method calls another
	 * method called end exercise, and if the user had pressed editQuestion a
	 * new question would be added to an existing exercise
	 * 
	 * @author hadeer
	 * @param addQuestion
	 * @param EndExercise
	 * @param exerciseid
	 * @param theQuestion
	 * @param Choice1
	 * @param Choice2
	 * @param Choice3
	 * @param Choice
	 * @param Marks
	 * @param comment
	 */
	public static void createQuestion(
			long addQuestion,
			long EndExercise,
			long editQuestion,
			long exerciseid,
			@Required(message = "Please Enter the question") String theQuestion,
			String Choice1,
			String Choice2,
			String Choice3,
			List<String> Choice,
			@Required(message = "Please Enter the marks of the question") String Marks) {
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			addQuestion(exerciseid);
		} else {
			long UserId = Long.parseLong(session.get("RegisteredUserId"));
			models.RegisteredUser user = models.RegisteredUser.findById(UserId);
			if (session.get("RegisteredUserId") != null) {
				models.Exercise exercise = models.Exercise.findById(exerciseid);
				int counter = 0;
				try {
					if (!theQuestion.equals("")) {
						int marks = Integer.parseInt(Marks);
						models.Question tempQuestion = new models.Question(
								theQuestion, marks, exerciseid);

						if (checkChoiceNull(Choice1) == true) {
							models.Choice tempchoice1 = new models.Choice(
									Choice1, tempQuestion.id);
							tempQuestion.getMyChoices().add(tempchoice1);
							tempchoice1.save();
							counter++;
						}
						if (checkChoiceNull(Choice2) == true) {
							models.Choice tempchoice2 = new models.Choice(
									Choice2, tempQuestion.id);
							tempQuestion.getMyChoices().add(tempchoice2);
							tempchoice2.save();
							counter++;
						}
						if (checkChoiceNull(Choice3) == true) {
							models.Choice tempchoice3 = new models.Choice(
									Choice3, tempQuestion.id);
							tempQuestion.getMyChoices().add(tempchoice3);
							tempchoice3.save();
							counter++;
						}
						if (Choice != null) {
							for (int i = 0; i < Choice.size(); i++) {
								if (checkChoiceNull(Choice.get(i)) == true) {
									models.Choice tempchoice = new models.Choice(
											Choice.get(i), tempQuestion.id);
									tempQuestion.getMyChoices().add(tempchoice);
									tempchoice.save();
									counter++;
								}

							}
						}

						if (counter < 2) {
							renderText("the options entred is less than 2");
						} else {

							exercise.getQuestions().add(tempQuestion);
							tempQuestion.save();
							if (addQuestion != 0) {
								addQuestion(exercise.id);
							} else {
								if (EndExercise != 0) {
									user.addPoints();
									LogRecord.createLog("New excercise "
											+ exercise.ExerciseName, user);
									controllers.ReviewRequests
											.sendRequests(exerciseid);
								} else {
									if (editQuestion != 0) {
										editExercise(exerciseid);
									}
								}
							}
						}
					} else {
						renderText("you didn't enter the content of the question");
					}
				} catch (NumberFormatException nfe) {
					renderText("the marks you entered is not a number");

				}
			} else {
				renderText("please log in first to create an exercise");

			}

		}
	}

	/***
	 * this method calls the page edit exercise which takes the list of
	 * questions and the exercise id if the user is the creator of the exercise
	 * 
	 * @author hadeer
	 * @param id
	 */
	public static void editExercise(long id) {
		long UserId = Long.parseLong(session.get("RegisteredUserId"));
		models.Exercise tempExercise = models.Exercise.findById(id);

		boolean authorized = false;
		if (UserId == tempExercise.getCreatorID()) {
			authorized = true;
			List<Question> theQuestions = tempExercise.getQuestions();
			render(theQuestions, tempExercise, authorized);
		} else {
			authorized = false;
			ReviewRequests.myCreatedExercises();
		}

		List<Question> theQuestions = tempExercise.getQuestions();
		render(theQuestions, tempExercise);

	}

	/***
	 * this method submits the content of the edited exercise to be replaced by
	 * the old content
	 * 
	 * @author hadeer
	 * @param theQuestion
	 * @param Choice
	 * @param marks
	 * @param exerciseid
	 */
	public static void submitEdit(
			long delete,
			@Required(message = "Please Enter the marks of the question") List<String> theQuestion,
			List<String> Choice,
			@Required(message = "Please Enter the marks of the question") List<String> marks,
			long exerciseid) {
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			editExercise(exerciseid);
		} else {
            if(delete == 0){
			long UserId = Long.parseLong(session.get("RegisteredUserId"));
			boolean check = false;
			models.Exercise tempexercise = models.Exercise.findById(exerciseid);
			int k = 0;
			int counter = 0;
			for (int i = 0; i < tempexercise.getQuestions().size(); i++) {
				if (!theQuestion.get(i).equals("")) {
					tempexercise.getQuestions().get(i)
							.setTheQuestion(theQuestion.get(i));
					tempexercise.save();
				} else {
					// check = true;
					renderText("you haven't entered thequestion");
				}
				try {
					int Marks = Integer.parseInt(marks.get(i));
					tempexercise.getQuestions().get(i).setMarks(Marks);
					tempexercise.save();
				} catch (NumberFormatException nfe) {
					// check = true;
					renderText("the marks you entered is not a number");

				}
				for (int j = 0; j < tempexercise.getQuestions().get(i)
						.getMyChoices().size(); j++) {
					if (!Choice.get(k).equals("")) {
						tempexercise.getQuestions().get(i).getMyChoices()
								.get(j).setChoice(Choice.get(k));
						k++;
						counter++;
						tempexercise.save();
					}

				}
				if (counter < 2) {
					renderText("the choices entered is less than two");
				}

			}
			ReviewRequests.myCreatedExercises();
		}else{
			models.Question.findById(delete)._delete();
			editExercise(exerciseid);
		}}
	}

	/**
	 * This method takes the ID and allow the creator to post model answers for
	 * the first question of the exercise
	 * 
	 * @author samar nassar
	 * 
	 * @param long id
	 */

	public static void postModelAnswer(long id) {

		int i = 0;
		Exercise exercise = Exercise.findById(id);
		Question questions;
		List<Choice> choices;
		choices = exercise.getQuestions().get(0).getMyChoices();
		questions = exercise.getQuestions().get(0);
		render(questions, choices, id, i);
	}

	/**
	 * This method takes the ID and allow the creator to post model answers for
	 * the rest of the exercise The user also can post comments on the model
	 * answer
	 * 
	 * @author samar nassar & aya alaa
	 * 
	 * @param String
	 *            answer
	 * @param int i
	 * @param id
	 * @param comment
	 */

	public static void nextpostmodelAnswer(String answer, int i, long id,
			String comment) {

		i++;

		Exercise exercise = Exercise.findById(id);
		Question questions;
		Question previousQuestion;
		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		RegisteredUser user = RegisteredUser.findById(registeredUser);

		if (i >= exercise.getQuestions().size()) {
			previousQuestion = exercise.getQuestions().get(i - 1);
			previousQuestion.setModelAnswer(answer);

			previousQuestion.setComment(comment);
			previousQuestion.save();

			user.addPoints();
			Application.viewProfile(user.id);

		}

		else {

			questions = exercise.getQuestions().get(i);
			previousQuestion = exercise.getQuestions().get(i - 1);
			previousQuestion.setModelAnswer(answer);
			previousQuestion.setComment(comment);
			previousQuestion.save();

			List<Choice> choices;
			choices = exercise.getQuestions().get(i).getMyChoices();
			render(questions, choices, i, id);
		}
	}

	/**
	 * This method takes the ID of a tutorial and renders all the exercises on
	 * this tutorial
	 * 
	 * 
	 * @author samar nassar
	 * 
	 * @param long tutId
	 */

	public static void chooseExercise(long tutorialId) {

		Tutorial tutorial = Tutorial.findById(tutorialId);
		List<Exercise> exercises = tutorial.getAvailableExercise();
		render(exercises);
	}

	/**
	 * This method takes the ID of a tutorial and views the first question in
	 * the exercise
	 * 
	 * 
	 * @author samar nassar
	 * 
	 * @param long tutId
	 */

	public static void viewExercise(long id) {
		int i = 0;

		if (session.get("RegisteredUserId") != null) {

			Exercise exercise = Exercise.findById(id);
			Question questions;
			List<Choice> choices;

			if (exercise.isPublished() == true) {
				if (exercise.isRandom == true) {
					Exercise ex = listOfRandomQuestions(id);
					questions = ex.questions.get(0);
					choices = ex.questions.get(0).getMyChoices();
					render(questions, id, i, choices);
				} else {

					questions = exercise.questions.get(0);
					choices = exercise.questions.get(0).getMyChoices();
					render(questions, id, i, choices);
				}

			}

			renderText("The Exercise is waiting to be published");
		}
		renderText("You are not allowed to take this exercise :(");
	}

	/**
	 * This method takes the ID of a tutorial and shows the rest of questions of
	 * the exercise
	 * 
	 * @author Samar Nassar
	 * 
	 * @param i
	 * @param long id
	 * @param String
	 *            answer
	 */

	public static void nextQuestion(int i, long id, String answer) {

		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		RegisteredUser user = RegisteredUser.findById(registeredUser);

		i = i + 1;
		Exercise exercise = Exercise.findById(id);
		Question questions;
		if (i >= exercise.questions.size()) {
			int s = checkAnswer(id, i, answer);
			Score mine = new Score(exercise.getId(), s, registeredUser);
			mine.save();
			exercise.setExerciseScore(s);
			exercise.save();
			user.scores.add(s);
			user.save();
			exercise.setScore(0);
			exercise.save();
			user.exerciseTaken.add(exercise);

			user.save();
			exercise.save();
			Exercises.endedExercise(id, s);

		} else {
			questions = exercise.questions.get(i);
			List<Choice> choices;
			choices = exercise.questions.get(i).getMyChoices();

			checkAnswer(id, i, answer);
			render(questions, choices, i, id);
		}
	}

	/**
	 * This method checks the answer of the user and the model answer and
	 * calculates the score
	 * 
	 * @author samar nassar
	 * 
	 * @param long id
	 * @param int i
	 * @param String
	 *            answer
	 */

	public static int checkAnswer(long id, int i, String answer) {

		Exercise exercise = Exercise.findById(id);
		Question previousQuestion;
		previousQuestion = exercise.getQuestions().get(i - 1);
		String modelAnswer = previousQuestion.getModelAnswer();
		int mark = previousQuestion.getMarks();
		int score = exercise.getScore();
		if (answer.equals(modelAnswer)) {

			score += mark;
			exercise.setScore(score);
			exercise.save();

		}

		return score;

	}

	/**
	 * This method takes the ID and shows the user's score
	 * 
	 * @author samar nassar
	 * 
	 * @param long id
	 * @param int score
	 */

	public static void endedExercise(long id, int s) {
		Exercise exercise = Exercise.findById(id);
		List<Question> allQuestions;
		allQuestions = exercise.getQuestions();
		ArrayList<String> modelAnswers = new ArrayList<String>();
		int totalScore = exercise.sumOfmarks(id);
		for (int i = 0; i < allQuestions.size(); i++) {
			String ma = allQuestions.get(i).getModelAnswer();
			modelAnswers.add(ma);

			if (i == allQuestions.size()) {
				renderText(modelAnswers);
			}

		}
		render(s, totalScore,id);
	}

	/**
	 * This method shows all the questions of the exercise in one page.
	 * 
	 * @author samar nassar
	 * 
	 * @param long id
	 */

	public static void allQuestions(long id) {
		models.Exercise exercise = models.Exercise.findById(id);
		if (exercise.isPublished() == true) {

			List<Question> questions;
			List<Choice> choices;

			if (exercise.isRandom == true) {
				Exercise ex = listOfRandomQuestions(id);
				questions = ex.questions;
				render(questions, id);
			} else {

				questions = exercise.getQuestions();

				render(questions, id);
			}

		}
		renderText("The Exercise is waiting to be published");
	}

	/**
	 * This method takes the list of answers for the user and the exercise id
	 * and calculate the score
	 * 
	 * @author samar nassar
	 * 
	 * @param list
	 *            <String> choice
	 * @param long id
	 */

	public static void correctanswers(List<String> choice, long id) {

		models.Exercise exercise = models.Exercise.findById(id);
		List<Question> quest = exercise.getQuestions();
		List<String> a = new ArrayList<String>();

		int j = 0;
		int i = 1;
		while (j < choice.size()) {

			String answer = choice.get(j);
			int x = checkAnswer(id, i, answer);

			j++;
			i++;

		}
		int score = exercise.getScore();
		Exercises.allModelAnswers(id, score);

	}

	/**
	 * This method takes the ID and the score that the user got and views all
	 * the model answer at the end of the exercise
	 * 
	 * @author samar nassar
	 * 
	 * @param long exercise id, score
	 */

	public static void allModelAnswers(long id, int score) {

		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		RegisteredUser user = RegisteredUser.findById(registeredUser);
		Exercise exercise = Exercise.findById(id);
		List<Question> allQuestions;
		allQuestions = exercise.getQuestions();
		ArrayList<String> modelAnswers = new ArrayList<String>();
		ArrayList<String> comment = new ArrayList<String>();
		int totalScore = exercise.sumOfmarks(id);

		for (int i = 0; i < allQuestions.size(); i++) {
			String ma = allQuestions.get(i).getModelAnswer();
			String comm = allQuestions.get(i).getComment();
			comment.add(comm);
			modelAnswers.add(ma);

			if (i == allQuestions.size()) {
				renderText(modelAnswers);
			}

		}

		Score mine = new Score(exercise.getId(), score, registeredUser);
		mine.save();
		exercise.setExerciseScore(score);
		exercise.save();
		user.scores.add(score);
		user.save();
		exercise.setScore(0);
		exercise.save();
		user.exerciseTaken.add(exercise);

		user.save();
		exercise.save();
		render(modelAnswers, score, totalScore, comment);
	}

	/**
	 * This method takes the ID and the number of question and render the model
	 * answer for this question
	 * 
	 * @author samar nassar
	 * 
	 * @param long tutId, number of question
	 */

	public static void maperQuestion(long id, int i) {
		Exercise exercise = Exercise.findById(id);
		Question quest;
		quest = exercise.getQuestions().get(i);
		String modelAnswer = quest.getModelAnswer();
		String comment = quest.getComment();
		if (quest.getModelAnswer() == null) {
			renderText("Sorry this exercise doesn't have a model answer and your score will be Zero");
		}
		renderText("This is the model answer:" + modelAnswer + "\n"
				+ "This is the comment:" + comment);

	}

	/***
	 * @author dana This method returns the list of questions of a certain
	 *         exercise
	 * @param exerciseid
	 * @return
	 */
	public static List<Question> exerciseQuestions(long exerciseid) {

		Exercise exercise = Exercise.findById(exerciseid);

		return (exercise.getQuestions());

	}

	/***
	 * @author dana This method saves the questions of a certain exercise in an
	 *         array
	 * @param exerciseid
	 * @return
	 */
	public static Question[] arrayOfQuestions(long exerciseid) {

		List<Question> questions = exerciseQuestions(exerciseid);
		int size = exerciseQuestions(exerciseid).size();
		Question[] question = new Question[size];
		for (int i = 0; i < question.length; i++) {
			question[i] = questions.get(i);

		}
		return question;
	}

	/***
	 * @author dana This method returns the array of questions in a random order
	 * @param exerciseid
	 * @return
	 */
	public static Question[] randomingQuestions(long exerciseid) {

		Random random = new Random();

		Question[] randomQuestions = arrayOfQuestions(exerciseid);

		for (int i = 0; i < randomQuestions.length - 1; i++) {

			int nextInt = random.nextInt(randomQuestions.length - i);

			Question q = randomQuestions[i + nextInt];

			randomQuestions[i + nextInt] = randomQuestions[i];

			randomQuestions[i] = q;

		}

		return randomQuestions;

	}

	/***
	 * @author dana This method saves the random array of questions in a list
	 * @param exerciseid
	 * @return
	 */
	public static Exercise listOfRandomQuestions(long exerciseid) {

		Question[] question = randomingQuestions(exerciseid);

		List<Question> listOfQuestions = new ArrayList<Question>();

		for (int i = 0; i < question.length; i++) {

			listOfQuestions.add(question[i]);

		}
		models.Exercise exercise = models.Exercise.findById(exerciseid);

		exercise.setQuestions(listOfQuestions);

		return exercise;

	}

	/***
	 * @author dana This method saves the random array of questions in a list
	 * @param exerciseid
	 * @return
	 */
	public static List<Question> listOfRandomQuestions2(long exerciseid) {

		Question[] question = randomingQuestions(exerciseid);

		List<Question> listOfQuestions = new ArrayList<Question>();

		for (int i = 0; i < question.length; i++) {

			listOfQuestions.add(question[i]);

		}

		return listOfQuestions;

	}

	/***
	 * @author dana This method shows the exercise
	 * @param exerciseid
	 */
	public static void showExercises(long id) {

		models.Exercise exercise = models.Exercise.findById(id);

		List<Question> questions;

		questions = exercise.getQuestions();

		render(questions, id);

	}

	/***
	 * @author Shahinda This method views the scores of all people who took a
	 *         certain exercise
	 * @param id
	 */
	public static void showScores(long id) {

		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		models.Exercise tempexercise = models.Exercise.findById(id);
		List<RegisteredUser> users = tempexercise.getPeopleAnswered();
		models.RegisteredUser tempregistereduser = models.RegisteredUser
				.findById(registeredUser);

		List<Integer> Score = new ArrayList<Integer>();
		for (int i = 0; i < tempexercise.getPeopleAnswered().size(); i++) {
			for (int k = 0; k < tempexercise.getPeopleAnswered().get(i).exerciseTaken
					.size(); k++) {
				if (tempexercise.id == tempexercise.getPeopleAnswered().get(i).exerciseTaken
						.get(i).id) {
					Score.add(tempregistereduser.scores.get(i));
				}
			}

		}

		render(users, Score);

	}

	/***
	 * @author shahinda This method deletes an exercise
	 * @param id
	 */
	public static void deleteExercise(long id) {
		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		models.RegisteredUser tempregistereduser = models.RegisteredUser
				.findById(registeredUser);
		models.Exercise tempexercise = models.Exercise.findById(id);
		List<Question> tempquestion = models.Question.find("myExercise=?",
				tempexercise).fetch();
		for (int i = 0; i < tempquestion.size(); i++) {
			List<Choice> tempchoice = models.Choice.find("myQuestion=?",
					tempquestion.get(i)).fetch();
			for (int j = 0; j < tempchoice.size(); j++) {
				tempchoice.get(j).delete();
			}
			tempquestion.get(i).delete();
		}
		List<RegisteredUser> allusers = models.RegisteredUser.findAll();
		for (int g = 0; g < allusers.size(); g++) {
			for (int l = 0; l < allusers.get(g).exerciseTaken.size(); l++) {
				if (allusers.get(g).exerciseTaken.get(l).equals(tempexercise)) {
					allusers.get(g).exerciseTaken.get(l).delete();
					allusers.get(g).scores.get(l);
				}

			}

		}
		List<CommunityList> allcommunitys = models.CommunityList.findAll();
		for (int q = 0; q < allcommunitys.size(); q++) {
			for (int r = 0; r < allcommunitys.get(q).recommendListExercise
					.size(); r++) {
				if (allcommunitys.get(q).recommendListExercise.get(r).equals(
						tempexercise)) {
					allcommunitys.get(q).recommendListExercise.get(r).delete();
				}
			}
		}
		tempexercise.delete();
		Application.viewProfile(id);
	}

	public static void deleteExercises(long id) {
		models.Exercise tempexercise = models.Exercise.findById(id);
		tempexercise.setPublished(false);
		tempexercise.save();

		renderText(tempexercise.isPublished());
	}

	/***
	 * @author Aya This method views the rank of the user who took the exercise
	 * @param id
	 * @return
	 */

	public static void viewRank(long id) {
		Exercise exercise = models.Exercise.findById(id);
		long registeredUser = Long.parseLong(session.get("RegisteredUserId"));
		List<Integer> rank = new ArrayList<Integer>();
		List<Integer> orderedlist = new ArrayList<Integer>();
		int max = exercise.getScores().get(0);
		RegisteredUser maxuser = exercise.getPeopleAnswered().get(0);
		List<RegisteredUser> orderregistereduser = new ArrayList<RegisteredUser>();
		for (int h = 0; h < exercise.getScores().size(); h++) {
			orderedlist.add(exercise.getScores().get(h));
			orderregistereduser.add(exercise.getPeopleAnswered().get(h));
		}
		for (int i = 0; i < orderedlist.size(); i++) {
			max = orderedlist.get(i);
			for (int k = i; k < orderedlist.size(); k++) {
				if (orderedlist.get(k) > max) {
					int temp = orderedlist.get(i);
					orderedlist.set(i, orderedlist.get(k));
					orderedlist.set(k, temp);
					RegisteredUser tempuser = orderregistereduser.get(i);
					orderregistereduser.set(i, orderregistereduser.get(k));
					orderregistereduser.set(k, tempuser);
				}
			}
			rank.add(i + 1);
		}

		render(rank, orderregistereduser);

	}
}
